package agorithm.week2.classOne;

import java.util.HashMap;
import java.util.Map;

/**
 * 146. LRU 缓存机制
 * 运用你所掌握的数据结构，设计和实现一个  LRU (最近最少使用) 缓存机制 。
 * 实现 LRUCache 类：
 *
 * LRUCache(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存
 * int get(int key) 如果关键字 key 存在于缓存中，则返回关键字的值，否则返回 -1 。
 * void put(int key, int value) 如果关键字已经存在，则变更其数据值；如果关键字不存在，则插入该组「关键字-值」。当缓存容量达到上限时，它应该在写入新数据之前删除最久未使用的数据值，从而为新的数据值留出空间。
 *
 *
 * 进阶：你是否可以在 O(1) 时间复杂度内完成这两种操作？
 */
public class LRUCache {
    private Map<Integer, ListNode> map ;
    private ListNode head;
    private ListNode tail;
    private int capacity;

    public static void main(String[] args) {
        LRUCache lruCache = new LRUCache(3);
        lruCache.put(1,3);
        lruCache.put(2,3);
        lruCache.get(1);
        lruCache.put(3,3);
        lruCache.get(2);
        lruCache.put(5,3);
    }

    public LRUCache(int capacity) {
        this.capacity = capacity;
        head = new ListNode();
        tail = new ListNode();
        head.next = tail;
        tail.pre = head;
        map = new HashMap<>(capacity);
    }

    public int get(int key) {
        if(!map.containsKey(key)) return -1;
        ListNode node =  map.get(key);
        this.removeNode(node.key,node.val);
        this.insertNode(node.key,node.val);
        return node.val;
    }

    public void put(int key, int value) {
        if(map.containsKey(key)){
            this.removeNode(key,value);
        }
        this.insertNode(key,value);
        if( map.size() > this.capacity){
            removeNode(tail.pre.key,tail.pre.val);
        }
    }

    private void insertNode(int key, int value){
        ListNode node = new ListNode(key,value);
        // 目前的头节点pre指向node,node的next指向目前的头节点
        node.next = head.next;
        head.next.pre = node;
        // 修改node节点的指针
        node.pre = head;
        head.next = node;

        map.put(key,node);
    }

    private void removeNode(int key, int value){
        ListNode node = map.get(key);
        node.pre.next = node.next;
        node.next.pre = node.pre;
        map.remove(key);
    }
}

class ListNode{
    public ListNode next;
    public ListNode pre;
    public int key;
    public int val;
    public ListNode(int key, int val){
        this.key = key;
        this.val = val;
    }
    public ListNode(){
    }
}